import { db } from '@/db'
import { videos, videoUpdateSchema } from '@/db/schema'
import { mux } from '@/lib/mux'
import { protectedProcedure, router } from '@/trpc/init'
import { TRPCError } from '@trpc/server'
import { and, eq } from 'drizzle-orm'
import { UTApi } from 'uploadthing/server'
import { z } from 'zod'

export const videosRouter = router({
  restoreThumbnail: protectedProcedure
    .input(z.object({ id: z.string().uuid() }))
    .mutation(async ({ ctx, input }) => {
      const { id: userId } = ctx.user

      const [existingVideo] = await db
        .select()
        .from(videos)
        .where(and(eq(videos.id, input.id), eq(videos.userId, userId)))

      if (!existingVideo) throw new TRPCError({ code: 'NOT_FOUND' })

      const utapi = new UTApi()

      if (existingVideo.thumbnailKey) {
        await utapi.deleteFiles(existingVideo.thumbnailKey)
        await db
          .update(videos)
          .set({
            thumbnailKey: null,
            thumbnailUrl: null
          })
          .where(and(eq(videos.id, input.id), eq(videos.userId, userId)))
      }

      const temptThumbnailUrl = `https://image.mux.com/${existingVideo.muxPlaybackId}/thumbnail.jpg`
      const uploadThumbnailUrl = await utapi.uploadFilesFromUrl(
        temptThumbnailUrl
      )

      if (!uploadThumbnailUrl)
        throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR' })

      const { key: thumbnailKey, url: thumbnailUrl } =
        uploadThumbnailUrl.data || {}

      const [updatedVideo] = await db
        .update(videos)
        .set({
          thumbnailUrl,
          thumbnailKey
        })
        .where(and(eq(videos.id, input.id), eq(videos.userId, userId)))
        .returning()

      return updatedVideo
    }),

  remove: protectedProcedure
    .input(z.object({ id: z.string().uuid() }))
    .mutation(async ({ ctx, input }) => {
      const { id: userId } = ctx.user

      const [removedVideo] = await db
        .delete(videos)
        .where(and(eq(videos.id, input.id!), eq(videos.userId, userId)))
        .returning()

      if (!removedVideo) throw new TRPCError({ code: 'NOT_FOUND' })

      if (removedVideo.thumbnailKey && removedVideo.previewKey) {
        const utapi = new UTApi()
        await utapi.deleteFiles([
          removedVideo.thumbnailKey,
          removedVideo.previewKey
        ])
      }

      return removedVideo
    }),

  update: protectedProcedure
    .input(videoUpdateSchema)
    .mutation(async ({ ctx, input }) => {
      const { id: userId } = ctx.user

      const [updatedVideo] = await db
        .update(videos)
        .set({
          title: input.title,
          description: input.description,
          categoryId: input.categoryId,
          visibility: input.visibility,
          updatedAt: new Date()
        })
        .where(and(eq(videos.id, input.id!), eq(videos.userId, userId)))
        .returning()

      if (!updatedVideo) throw new TRPCError({ code: 'NOT_FOUND' })
      return updatedVideo
    }),

  create: protectedProcedure.mutation(async ({ ctx }) => {
    const { id: userId } = ctx.user

    const upload = await mux.video.uploads.create({
      cors_origin: '*',
      new_asset_settings: {
        passthrough: userId,
        playback_policy: ['public'],
        input: [
          {
            generated_subtitles: [
              {
                language_code: 'en',
                name: 'English'
              }
            ]
          }
        ]
      }
    })

    const [video] = await db
      .insert(videos)
      .values({
        userId,
        title: 'Untitled',
        muxStatus: 'waiting',
        muxUploadId: upload.id
      })
      .returning()

    return { video, url: upload.url }
  })
})
